﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using System;
using System.Runtime.Serialization.Formatters.Binary;

public class BundleManager :MonoBehaviour
{

    //服务器资源你版本
    public string serverVersion;
    //本地资源版本
    // public string localVersion;
    /// <summary>
    /// 服务器资源地址
    /// </summary>
    [HideInInspector]
    public string serveResPath;
    private AssetBundle baseAB;
    private AssetBundle currentAB;

    public bool initBaseOver = false;
    public bool initRabbitOver = false;

    string oldVersion = "";


    /// <summary>
    /// 初始化包内原始资源数据
    /// </summary>
    public void InitOrginData()
    {
        initBaseOver = false;
        initRabbitOver = false;
    }

    public T LoadBaseAsset<T>(string name) where T : UnityEngine.Object
    {
        if (baseAB)
        {
            return baseAB.LoadAsset<T>(name);
        }
        return null;
    }

    public T LoadAsset<T>(string name) where T : UnityEngine.Object
    {
        if (currentAB)
        {
            return currentAB.LoadAsset<T>(name);
        }
        return null;
    }

    //获取服务器上的资源
    IEnumerator MyUnityWebRequest(string uri, Action<DownloadHandler> succes, Action err, Action<float> processAction)
    {
        Debug.Log("资源地址：" + uri);
        //要使用这种方式获取资源,才能访问到他的字节流
        using (UnityWebRequest request = UnityWebRequest.Get(uri))
        {
            //这个方法主要是用来获取AssetBundle资源的,但他下载到的数据是不给访问的,如果想访问或者保存下载回来的数据用上面的UnityWebRequest.Get()
            //request = UnityWebRequestAssetBundle.GetAssetBundle(pathMP);
            yield return request.SendWebRequest();
            while (!request.isDone)
            {
                processAction(request.downloadProgress);
                yield return null;
            }
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError("请求失败");
                err();
                yield break;
            }
            //保存下载回来的文件
            if (request.isDone)
            {
                succes(request.downloadHandler);
            }
        }
    }

    /// <summary>
    /// 从原始资源包获取资源
    /// </summary>
    /// <param name="uri">资源包内路径</param>
    /// <param name="savePath">保存的路径</param>
    /// <param name="sucess">成功回调</param>
    /// <param name="process">进度</param>
    /// <returns></returns>
    IEnumerator InitLoaclRes(string uri, string savePath, Action sucess, Action err, Action<float> processAction)
    {
        //要使用这种方式获取资源,才能访问到他的字节流
        using (UnityWebRequest request = UnityWebRequest.Get(uri))
        {

            //这个方法主要是用来获取AssetBundle资源的,但他下载到的数据是不给访问的,如果想访问或者保存下载回来的数据用上面的UnityWebRequest.Get()
            //request = UnityWebRequestAssetBundle.GetAssetBundle(pathMP); 
            yield return request.SendWebRequest();
            while (!request.isDone)
            {
                Debug.Log(uri + "下载进度：" + request.downloadProgress);
                processAction(request.downloadProgress);
                yield return null;
            }
            if (request.isNetworkError || request.isHttpError)
            {
                err();
            }
            //保存下载回来的文件
            if (request.isDone)
            {
                Debug.Log("开始写入磁盘");
                //构造文件流
                using (FileStream fs = File.Create(savePath))
                {
                    //将字节流写入文件里,request.downloadHandler.data可以获取到下载资源的字节流
                    fs.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);

                    fs.Flush();     //文件写入存储到硬盘
                    fs.Close();     //关闭文件流对象
                    fs.Dispose();   //销毁文件对象
                    Debug.Log(savePath + "写入磁盘成功");
                    sucess?.Invoke();
                }
            }
        }

    }

    //--------------------------------------------初始化资源----------------------------------------------------------

    public float currentProcess = 0;
    /// <summary>
    /// 包内路径
    /// </summary>
    string orgCachePath;
    int curretnDownIndex;

    int downCount;
    BundleInfos localBundleInfos;
    string resPath;
    /// <summary>
    /// 缓存路径
    /// </summary>
    string savePath;
    string currentDownBundleName;
    string bundleversionLocalPath;

    /// <summary>
    /// 检查本地是否有版本文件
    /// </summary>
    public void CheckBundleVersionTxt()
    {
#if UNITY_EDITOR
        if (true)
        {
            localBundleInfos = JsonUtility.FromJson<BundleInfos>(File.ReadAllText(Application.streamingAssetsPath + "/bundleversion.txt"));
            AssetBundle assetBundle;
            foreach (var item in localBundleInfos.bundles)
            {
                assetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + localBundleInfos.version + "/" + item.name);
                switch (item.name)
                {
                    case "base":
                        baseAB = assetBundle;
                        break;
                    case "RabbitRes":
                        currentAB = assetBundle;
                        break;
                }
            }
            currentProcess = 1;
            Debug.Log("编辑器bundle加载完毕");
            return;
        }

        orgCachePath = Application.streamingAssetsPath + "/";
#else
        orgCachePath = "jar:file://" + Application.dataPath + "!/assets/"; 
#endif 
        bundleversionLocalPath = orgCachePath + "bundleversion.txt";
        savePath = Application.persistentDataPath + "/bundleversion.txt";

        if (File.Exists(savePath))
        {
            //版本文件存在，检查版本更新
            Debug.Log("初始化-  本地版本文件存在，检查版本更新");
            if (CheckResCompleteness())
            {
                CheckServerVersion();
            }
            else
            {
                Debug.Log("资源不完整，重新拷贝资源");
                CopyRes();
            }
        }
        else
        {
            CopyRes();
        }
    }

    void CopyRes()
    {
        StartCoroutine(
           //版本文件不存在或文件不完整，读取包内资源 
           InitLoaclRes(bundleversionLocalPath, savePath, () =>
           {
               Debug.Log("读取包内 资源，加载完成");
               localBundleInfos = JsonUtility.FromJson<BundleInfos>(File.ReadAllText(savePath));
               downCount = localBundleInfos.bundles.Count;
               if (localBundleInfos != null && localBundleInfos.bundles.Count > 0)
               {
                   curretnDownIndex = 0;
                   Debug.Log("将包内 bundleversion.txt 文件拷贝到缓存文件夹中");
#if UNITY_EDITOR
                   resPath = Application.streamingAssetsPath + "/" + localBundleInfos.version;
#else
                   resPath = "jar:file://" + Application.dataPath + "!/assets/" + localBundleInfos.version; 
#endif  
                   string cachePath = Application.persistentDataPath + "/" + localBundleInfos.version;
                   if (!Directory.Exists(cachePath))
                   {
                       Directory.CreateDirectory(cachePath);
                   }
                   LoadOrginRes(resPath);
               }
               else
               {
                   //版本文件内容为空，检查版本更新
                   CheckServerVersion();
               }

           }, () =>
           {
               Debug.Log("bundleversion.txt");
           }, (process) =>
           {

           }));
    }

    /// <summary>
    /// 加载包内原始资源
    /// </summary>
    private void LoadOrginRes(string resPath)
    {
        Debug.Log("加载包内原始资源" + resPath);
        if (curretnDownIndex >= downCount)
        {
            Debug.Log("本地资源加载完毕");
            CheckServerVersion();
        }
        else
        {
            currentDownBundleName = localBundleInfos.bundles[curretnDownIndex].name;
            StartCoroutine(
                InitLoaclRes(resPath + "/" + currentDownBundleName,
                Application.persistentDataPath + "/" + localBundleInfos.version + "/" + currentDownBundleName,
                () =>
                {
                    currentProcess = ((curretnDownIndex + 1) / downCount) * 0.5f;
                     curretnDownIndex++;
                    LoadOrginRes(resPath);
                },
                () =>
                {
                    Debug.Log(currentDownBundleName + "资源加载失败");
                },
                (process) =>
                {
                    currentProcess = ((curretnDownIndex + 1) / downCount) * process;
                 }
             ));

        }
    }
    //--------------------------------------------检查版本更新--------------------------------------------------------
    private void CheckServerVersion()
    {
        // if (HttpManager.Instance.NetAvailable)
        if (true)
        {
            //有网络
            if (File.Exists(savePath))
            {
                //本地版本文件存在，下载服务器版本文件
                Debug.Log("本地版本文件存在，下载服务器版本文件");
                CheckServeBundleTxt();
            }
            else
            {
                //版本文件不存在，将服务器上的初始资源全部下载
                Debug.Log("版本文件不存在，将服务器上的初始资源全部下载");
                LoadServeBundle();
            }
        }
        else
        {
            //无网络 
            Debug.Log("无网络，加载本地bundle资源");
            LoadResFromFile_Loacl();
        }
    }

    BundleInfos serveBundleInfos;
    List<string> upDataResList = new List<string>();
    /// <summary>
    /// 下载服务器版本文件，与本地对比文件MD5
    /// </summary>
    private void CheckServeBundleTxt()
    {
        localBundleInfos = JsonUtility.FromJson<BundleInfos>(File.ReadAllText(savePath));
        string resPah = serveResPath + "/bundleversion.txt";//服务器资源地址
        StartCoroutine(MyUnityWebRequest(resPah, (downloadHander) =>
        {
            serveBundleInfos = JsonUtility.FromJson<BundleInfos>(downloadHander.text.Replace("\\", ""));

            if (serverVersion == localBundleInfos.version)
            {
                Debug.Log("资源版本相同");
                for (int i = 0; i < serveBundleInfos.bundles.Count; i++)
                {
                    if (serveBundleInfos.bundles[i].md5 != localBundleInfos.bundles[i].md5 || localBundleInfos.bundles[i] == null || localBundleInfos.bundles[i].md5 == null)
                    {
                        upDataResList.Add(serveBundleInfos.bundles[i].name);
                    }
                }
                curretnDownIndex = 0;
                downCount = upDataResList.Count;
                if (downCount > 0)
                {
                    Debug.Log("更新资源");
                    DownLoadUpDateRes();
                }
                else
                {
                    //无资源更新，加载本地bundle资源
                    Debug.Log("无资源更新，加载本地bundle资源");
                    LoadResFromFile_Server();
                }
            }
            else
            {
                Debug.Log("资源版本不相同");
                Directory.Delete(Application.persistentDataPath + "/" + localBundleInfos.version, true);
                string strPath = Application.persistentDataPath + "/" + serverVersion;
                if (!Directory.Exists(strPath))
                {
                    Directory.CreateDirectory(strPath);
                }
                for (int i = 0; i < serveBundleInfos.bundles.Count; i++)
                {
                    upDataResList.Add(serveBundleInfos.bundles[i].name);
                }
                curretnDownIndex = 0;
                downCount = upDataResList.Count;
                DownLoadUpDateRes();
            }
        }, () =>
        {
            //下载失败
            Debug.LogError("下载 bundleversion.txt 失败");
        }, (process) =>
        {
            Debug.Log("下载 bundleversion.txt 下载进度" + process);
        }));
    }

    /// <summary>
    /// 下载服务器版本文件,并下载文件内的bundle
    /// </summary>
    private void LoadServeBundle()
    {
        string resPah = serveResPath + "/bundleversion.txt";//服务器资源地址
        StartCoroutine(MyUnityWebRequest(resPah, (downloadHander) =>
        {
            //bundleversion.txt 下载成功
            serveBundleInfos = JsonUtility.FromJson<BundleInfos>(downloadHander.text.Replace("\\", ""));

            for (int i = 0; i < serveBundleInfos.bundles.Count; i++)
            {
                upDataResList.Add(serveBundleInfos.bundles[i].name);
            }
            curretnDownIndex = 0;
            downCount = upDataResList.Count;
            DownLoadUpDateRes();
        }, () =>
        {
            //下载失败
            Debug.LogError("下载 bundleversion.txt 失败");
        }, (process) =>
        {
            Debug.Log("下载 bundleversion.txt 下载进度" + process);
        }));
    }

    /// <summary>
    /// 本地需要更新的资源
    /// </summary>
    private void DownLoadUpDateRes()
    {
        if (curretnDownIndex >= downCount)
        {
            Debug.Log("更新资源下载完毕");

            serveBundleInfos.version = serverVersion;
            File.WriteAllText(savePath, JsonUtility.ToJson(serveBundleInfos));
            LoadResFromFile_Server();
        }
        else
        {
            string resPah = serveResPath + "/" + serverVersion + "/";//服务器资源地址
            currentDownBundleName = upDataResList[curretnDownIndex];
            StartCoroutine(MyUnityWebRequest(resPah + currentDownBundleName, (downloadHander) =>
            {
                currentProcess = 0.5f + ((curretnDownIndex + 1) / downCount) * 0.5f;
                Debug.Log(currentDownBundleName + "资源下载进度：" + currentProcess);
                curretnDownIndex++;

                Debug.Log("开始写入磁盘");
                //构造文件流
                using (FileStream fs = File.Create(Application.persistentDataPath + "/" + serverVersion + "/" + currentDownBundleName))
                {
                    //将字节流写入文件里,request.downloadHandler.data可以获取到下载资源的字节流
                    fs.Write(downloadHander.data, 0, downloadHander.data.Length);

                    fs.Flush();     //文件写入存储到硬盘
                    fs.Close();     //关闭文件流对象
                    fs.Dispose();   //销毁文件对象
                    Debug.Log(savePath + "写入磁盘成功");
                }

                DownLoadUpDateRes();
            }, () =>
            {
                //下载失败
                Debug.LogError("下载 bundleversion.txt 失败");
            }, (process) =>
            {
                currentProcess = 0.5f + (((curretnDownIndex + 1) / downCount)) * process * 0.5f;
                Debug.Log("更新资源 下载进度" + process);
            }));
        }
    }

    /// <summary>
    /// 从服务器的bundleVersion文件中加载Bundle
    /// </summary>
    void LoadResFromFile_Server()
    {
        AssetBundle assetBundle;
        foreach (var item in serveBundleInfos.bundles)
        {
            assetBundle = AssetBundle.LoadFromFile(Application.persistentDataPath + "/" + serverVersion + "/" + item.name);
            switch (item.name)
            {
                case "base":
                    baseAB = assetBundle;
                    break;
                case "RabbitRes":
                    currentAB = assetBundle;
                    break;
            }
        }
        currentProcess = 1;
        Debug.Log("bundle加载完毕");
    }

    /// <summary>
    /// 从本地的bundleVersion文件中加载Bundle
    /// </summary>
    void LoadResFromFile_Loacl()
    {
        AssetBundle assetBundle;
        foreach (var item in localBundleInfos.bundles)
        {
            assetBundle = AssetBundle.LoadFromFile(Application.persistentDataPath + "/" + localBundleInfos.version + "/" + item.name);
            switch (item.name)
            {
                case "base":
                    baseAB = assetBundle;
                    break;
                case "RabbitRes":
                    currentAB = assetBundle;
                    break;
            }
        }
        currentProcess = 1;
        Debug.Log("bundle加载完毕");
    }

    /// <summary>
    /// 检查本地资源的完整性
    /// </summary>
    bool CheckResCompleteness()
    {
        localBundleInfos = JsonUtility.FromJson<BundleInfos>(File.ReadAllText(savePath));
        bool completeness = true;
        foreach (var item in localBundleInfos.bundles)
        {
            if (!File.Exists(Application.persistentDataPath + "/" + localBundleInfos.version + "/" + item.name))
            {
                completeness = false;
            }
        }
        Debug.Log("本地资源完整性检查完毕");
        return completeness;
    }

}


[System.Serializable]
public class BundleInfo
{
    public string name;
    public string md5;
    public long size;
}



[System.Serializable]
public class BundleInfos
{
    public string version;
    public List<BundleInfo> bundles = new List<BundleInfo>();
}
